/**
 * package universe is in
 */
package Model;

import java.io.Serializable;
import java.util.*;
/**
 * Universe class will keep track of the player as he/she 
 * traverses the universe. The class will also
 * generate solar systems to fill the universe.
 * @author Ben
 * @version 1
 */
public class Universe implements Serializable {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * random generator
	 */
	private final Random generator = new Random();
	
	/**
	 * local integer array
	 */
	private final List<Integer> locals = new ArrayList<Integer>();
	
	/**
	 * loop variables
	 */
	private int i = 0, j = 0, k = 1;
	
	/**
	 * universe height
	 */
	private final int uniHeight = 150;
	
	/**
	 * universe width
	 */
	private final int uniWidth = 150;
	
	/**
	 * actual universe, solarsystem 2x2 array
	 */
	private final SolarSystem[][] uni = new SolarSystem[uniHeight][uniWidth];
	
	/**
	 * player location in universe grid
	 */
	private final int[] playerLoc = {75, 75};
	/*
	 * playerLoc represents player location in 
	 * the form of x y coordinates that corresponds to 
	 * solar systems
	 */
	
	/**
	 * list of names to be used for solar systems
	 */
	private final String[] solarSystemNames = {
		    "Acamar",
		    "Courteney",	// After Courteney Cox...
		    "Daled",
		    "Fourmi",		// An ant, in French
		    "Frolix",		// A solar system in one of Philip K. Dick's novels
		    "Gemulon",
		    "Ran",			// A film by Akira Kurosawa
		    "Styris",
		    "Talani",
		    "Myrthe",		// The name of my daughter
		    "Nelvana",
		    "Nix",			// An interesting spelling of a word meaning "nothing" in Dutch
		    "Omega",		// The end of it all
		    "Regulas",
		    "Drema",
		    "Endor",
		    "Esmee",		// One of the witches in Pratchett's Discworld
		    "Damast",
		    "Davlos",
		    "Rakhar",
		    "Exo",
		    "Ferris",		// Iron
		    "Festen",		// A great Scandinavian movie
		    "Guinifer",		// One way of writing the name of king Arthur's wife
		    "Hades",		// The underworld
		    "Nyle",			// An interesting spelling of the great river
		    "Odet",
		    "Og",			// The last of the witches in Pratchett's Discworld
		    "Hamlet",		// From Shakespeare
		    "Helena",		// Of Troy
		    "Hulst",		// A Dutch plant
		    "Iodine",		// An element
		    "Iralius",
		    "Janus",		// A seldom encountered Dutch boy's name
		    "Japori",
		    "Kira",			// My dog's name
		    "Klaatu",		// From a classic SF movie
		    "Relva",
		    "Rhymus",
		    "Rochani",
		    "Jarada",
		    "Jason",		// A Greek hero
		    "Kaylon",
		    "Khefka",
		    "Rubicum",		// The river Caesar crossed to get into Rome
		    "Rutia",
		    "Laertes",		// A king in a Greek tragedy
		    "Largo",
		    "Adahn",		// The alternate personality for The Nameless One in "Planescape: Torment"
		    "Aldea",
		    "Andevian",
		    "Brax",			// One of the heroes in Master of Magic
		    "Bretel",		// This is a Dutch device for keeping your pants up.
		    "Calondia",
		    "Campor",
		    "Capelle",		// The city I lived in while programming this game
		    "Carzon",
		    "Castor",		// A Greek demi-god
		    "Melina",
		    "Mentar",		// The Psilon home system in Master of Orion
		    "Merik",
		    "Mintaka",
		    "Deneb",
		    "Deneva",
		    "Zalkon",
		    "Picard",		// The enigmatic captain from ST:TNG
		    "Pollux",		// Brother of Castor
		    "Quator",
		    "Sarpeidon",
		    "Sefalla",
		    "Cestus",
		    "Cheron",		
		    "Lave",			// The starting system in Elite
		    "Ligon",
		    "Lowry",		// The name of the "hero" in Terry Gilliam's "Brazil"
		    "Magrat",		// The second of the witches in Pratchett's Discworld
		    "Malcoria",
		    "Seltrice",
		    "Sigma",
		    "Sol",			// That's our own solar system
		    "Antedi",
		    "Balosnee",
		    "Baratas",
		    "Somari",
		    "Tamus",
		    "Devidia",
		    "Draylon",
		    "Klaestron",
		    "Korma",		// An Indian sauce
		    "Kravat",		// Interesting spelling of the French word for "tie"
		    "Krios",
		    "Montor",		// A city in Ultima III and Ultima VII part 2
		    "Mordan",
		    "Stakoron",
		    "Omphalos",		// Greek for navel
		    "Orias",
		    "Othello",		// From Shakespeare
		    "Parade",		// This word means the same in Dutch and in English
		    "Penthara",
		    "Utopia",		// The ultimate goal
		    "Vadera",
		    "Vagra",
		    "Vandor",
		    "Ventax",
		    "Xenon",
		    "Xerxes",		// A Greek hero
		    "Yew",			// A city which is in almost all of the Ultima games
		    "Yojimbo",		// A film by Akira Kurosawa
		    "Tantalos",		// A king from a Greek tragedy
		    "Tanuga",
		    "Tarchannen",
		    "Terosa",
		    "Thera",		// A seldom encountered Dutch girl's name
		    "Titan",		// The largest moon of Jupiter
		    "Torin",		// A hero from Master of Magic
		    "Triacus",
		    "Turkana",
		    "Tyrus",
		    "Umberlee",		// A god from AD&D, which has a prominent role in Baldur's Gate
		    "Zuul"			// From the first Ghostbusters movie
		};
	
	/**
	 * This is the Universe Constructor. It 
	 * creates a universe object randomly fills a 150 x 150 array 
	 * with solar systems of random tech levels. The 
	 * solar systems will be named from the string
	 * of possible solar system names aptly named, solarSystemNames.
	 */
	public Universe(){
		while (j < uniHeight){
			while (i < uniWidth){
				uni[i][j] = new SolarSystem(generator.nextInt(8) + 1, 
						solarSystemNames[k]);
				i = i + (generator.nextInt(60) + 5);
				k++;
				if (k == solarSystemNames.length - 1){
					break;
				}
			}
			j = j + 2 + generator.nextInt(8);
			i -= 150;
			if (k == solarSystemNames.length - 1){
				break;
			}
		}
	}
	
	/**
	 * Returns the constructed universe.
	 * @return the universe
	 */
	public SolarSystem[][] getUniverse(){
		return uni;
	}
	
	/**
	 * Returns the player's location.
	 * @return the location of the player in the form of xy coordinates
	 */
	public int[] getPlayerLoc(){
		return playerLoc;
	}
	
	/**
	 * getter for current planet
	 * @return current planet
	 */
	public Planet getCurrentPlanet(){
		SolarSystem ss = uni[playerLoc[0]][playerLoc[1]];
		return ss.getCurrentPlanet();
	}//end method getCurrentPlanet
	
	/**
	 * Sets the player's location.
	 * @param x the x coordinate of the solar system that the player is at
	 * @param y the y coordinate of the solar system that the player is at
	 */
	public void setPlayerLoc(int x, int y){
		playerLoc[0] = x;
		playerLoc[1] = y;
	}
	
	/**
	 * Used to determine which planets are in range for the player to fly to.
	 * 
	 * @param int fuelSize uses the players ship fuel 
	 * tank size as a numerical value for the 
	 * distance the player can travel.
	 */
	public void inRange(int fuelSize){
		fuelSize = fuelSize * 2;
		final int x = playerLoc[0];
		final int y = playerLoc[1];
		
		for (int i=0; i < uni.length; i++){
			for (int j=0; j < uni[0].length; j++){
				if (uni[i][j] != null){
					uni[i][j].setInRange(false);
				}
			}
		}
		
		for (int i=0; i < uni.length; i++) {
			for (int j=0; j < uni[0].length; j++){
				if (uni[i][j] != null){
					if (manhattanDist(x, y, i, j) <= fuelSize){
						uni[i][j].setInRange(true);
					}
				}
			}
		}
	}//end method inRange
	
	/**
	 * Helper function used to determine the minimum distance 
	 * between two squares on a grid.
	 * 
	 * @param startX the starting x location
	 * @param startY the starting y location
	 * @param endX the final x location
	 * @param endY the final y location
	 * @return the total distance between two points
	 *  on a grid, without the ability to move diagonally.
	 */
	private int manhattanDist(int startX, int startY, int endX, int endY){
		int output = 0;
		if (startX > endX) {
			output += (startX - endX);
		} else {
			output += (endX - startX);
		}
		if (startY > endY) {
			output += (startY - endY);
		} else {
			output += (endY - startY);
		}
		return output;
	}//end method manhattanDist
	
	/**
	 * Returns the x y coordinates of the solar systems that are within range in the 
	 * universe.
	 * @return an arraylist of ints, each odd and
	 *  even location represent x and y coordinates
	 * of a solar system that is in range
	 */
	public List<Integer> getLocals(){
		return locals;
	}
	
	/**
	 * tostring method for universe
	 * @return the freakin universe
	 */
	public String toString(){
		return "THE UNIVERSE";
	}
}
